package cn.kilo.infrastructure.persistent.redis;

import cn.kilo.domain.model.order.vo.OrderStatusVO;
import cn.kilo.infrastructure.persistent.po.Order;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.*;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.Duration;
import java.util.Collection;
import java.util.concurrent.TimeUnit;

/**
 * Redis 服务 - Redisson
 *
 * @author kilok
 */
@Service("redissonService")
@Slf4j
public class RedissonService implements IRedisService {

    @Resource
    private RedissonClient redissonClient;

    @Override
    public <T> void setValue(String key, T value) {
        redissonClient.<T>getBucket(key).set(value);
    }

    @Override
    public <T> void setValue(String key, T value, long expired) {
        RBucket<T> bucket = redissonClient.getBucket(key);
        bucket.set(value, Duration.ofMillis(expired));
    }

    @Override
    public <T> T getValue(String key) {
        return redissonClient.<T>getBucket(key).get();
    }

    @Override
    public <T> RQueue<T> getQueue(String key) {
        return redissonClient.getQueue(key);
    }

    @Override
    public <T> RBlockingQueue<T> getBlockingQueue(String key) {
        return redissonClient.getBlockingQueue(key);
    }

    @Override
    public <T> RDelayedQueue<T> getDelayedQueue(RBlockingQueue<T> rBlockingQueue) {
        return redissonClient.getDelayedQueue(rBlockingQueue);
    }

    @Override
    public void setAtomicLong(String key, long value) {
        redissonClient.getAtomicLong(key).set(value);
    }

    @Override
    public Long getAtomicLong(String key) {
        return redissonClient.getAtomicLong(key).get();
    }

    @Override
    public long incr(String key) {
        return redissonClient.getAtomicLong(key).incrementAndGet();
    }

    @Override
    public long incrBy(String key, long delta) {
        return redissonClient.getAtomicLong(key).addAndGet(delta);
    }

    @Override
    public long decr(String key) {
        return redissonClient.getAtomicLong(key).decrementAndGet();
    }

    @Override
    public long decrBy(String key, long delta) {
        return redissonClient.getAtomicLong(key).addAndGet(-delta);
    }

    @Override
    public void remove(String key) {
        redissonClient.getBucket(key).delete();
    }

    @Override
    public boolean isExists(String key) {
        return redissonClient.getBucket(key).isExists();
    }

    @Override
    public void addToSet(String key, String value) {
        RSet<String> set = redissonClient.getSet(key);
        set.add(value);
    }

    @Override
    public boolean isSetMember(String key, String value) {
        RSet<String> set = redissonClient.getSet(key);
        return set.contains(value);
    }

    @Override
    public void addToList(String key, String value) {
        RList<String> list = redissonClient.getList(key);
        list.add(value);
    }

    @Override
    public String getFromList(String key, int index) {
        RList<String> list = redissonClient.getList(key);
        return list.get(index);
    }

    @Override
    public <K, V> RMap<K, V> getMap(String key) {
        return redissonClient.getMap(key);
    }

    @Override
    public void addToMap(String key, String field, String value) {
        RMap<String, String> map = redissonClient.getMap(key);
        map.put(field, value);
    }

    @Override
    public String getFromMap(String key, String field) {
        RMap<String, String> map = redissonClient.getMap(key);
        return map.get(field);
    }

    @Override
    public <K, V> V getFromMap(String key, K field) {
        return redissonClient.<K, V>getMap(key).get(field);
    }

    @Override
    public void addToSortedSet(String key, OrderStatusVO value) {
        long score=System.currentTimeMillis()/1000;
        RScoredSortedSet<OrderStatusVO> scoredSortedSet = redissonClient.getScoredSortedSet(key);
        scoredSortedSet.addAsync(score,value);
    }

    @Override
    public <T> void addObjectToSortedSet(String key, T value) {
        // TODO: 2024/5/14 倘若之后让按照时间增长提高一个订单的优先级就重写一个关于score的计算方法
        long score=System.currentTimeMillis()/1000;
        RScoredSortedSet<Object> sortedSet=redissonClient.getScoredSortedSet(key);
        sortedSet.addAsync(score,value);
    }

    @Override
    public RLock getLock(String key) {
        return redissonClient.getLock(key);
    }

    @Override
    public RLock getFairLock(String key) {
        return redissonClient.getFairLock(key);
    }

    @Override
    public RReadWriteLock getReadWriteLock(String key) {
        return redissonClient.getReadWriteLock(key);
    }

    @Override
    public RSemaphore getSemaphore(String key) {
        return redissonClient.getSemaphore(key);
    }

    @Override
    public RPermitExpirableSemaphore getPermitExpirableSemaphore(String key) {
        return redissonClient.getPermitExpirableSemaphore(key);
    }

    @Override
    public RCountDownLatch getCountDownLatch(String key) {
        return redissonClient.getCountDownLatch(key);
    }

    @Override
    public <T> RBloomFilter<T> getBloomFilter(String key) {
        return redissonClient.getBloomFilter(key);
    }

    @Override
    public Boolean setNx(String key) {
        return redissonClient.getBucket(key).trySet("lock",5, TimeUnit.SECONDS);
    }

    @Override
    public RScoredSortedSet<Order> getSortedSet(String key) {
        return redissonClient.getScoredSortedSet(key);
    }

    @Override
    public void deleteSortedSet(OrderStatusVO order, String key) {
        log.info("cacheKey:{}",key);
        RScoredSortedSet<Object> scoredSortedSet = redissonClient.getScoredSortedSet(key);
        scoredSortedSet.removeAsync(order);
    }

    @Override
    public Collection<Object> getScoreSortedSet(String cacheKey) {
        RScoredSortedSet<Object> scoredSortedSet = redissonClient.getScoredSortedSet(cacheKey);
        Collection<Object> objects = scoredSortedSet.valueRange(0, -1);
        return objects;
    }

    @Override
    public Collection<Object> getScoreSortedSetAndDelete(String cacheKey) {
        RScoredSortedSet<Object> scoredSortedSet = redissonClient.getScoredSortedSet(cacheKey);
        Collection<Object> objects = scoredSortedSet.valueRange(0, -1);
        scoredSortedSet.removeAll(objects);
        return objects;
    }

    @Override
    public Collection<Object> getSortedSetByNumber(String key, Integer number) {
        RScoredSortedSet<Object> scoredSortedSet=redissonClient.getScoredSortedSet(key);
        Collection<Object> objects = scoredSortedSet.valueRange(0, -1);
        return objects;
    }

}
